package com.xingkeduo.business.user.domain;

import com.xingkeduo.business.user.activity.UserInviteReceiveCouponService;
import com.xingkeduo.business.user.event.EventHandleService;
import com.xingkeduo.business.user.event.QRCodeDTO;
import com.xingkeduo.business.user.service.*;
import com.xingkeduo.pojo.dto.OrderCraftsmanResponseDTO;
import com.xingkeduo.pojo.dto.ScanDTO;
import com.xingkeduo.pojo.dto.UserDTO;
import com.xingkeduo.pojo.enums.*;
import com.xingkeduo.pojo.query.ConsumerFileQO;
import com.xingkeduo.pojo.query.ConsumerRelateQO;
import com.xingkeduo.pojo.query.ShareQO;
import com.xingkeduo.pojo.query.WechatQrcodeQO;
import com.xingkeduo.pojo.table.*;
import com.xingkeduo.pojo.utils.Base64Utils;
import com.xingkeduo.pojo.utils.ConsumerUtils;
import com.xingkeduo.util.pojo.enums.YesNoEnum;
import com.xingkeduo.util.pojo.exception.DataException;
import com.xingkeduo.util.pojo.exception.InputParamException;
import com.xingkeduo.util.pojo.exception.SystemException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户邀请
 *
 * @Description:
 * @Author:gaozifeng
 * @Date 2019/7/10 17:19
 **/
@Slf4j
@Component
public class ConsumerInviteDomain {

    @Resource
    private WechatQrcodeService wechatQrcodeService;
    @Resource
    private ShareService shareService;
    @Resource
    private FeignDomain feignDomain;
    @Resource
    private ConsumerService consumerService;
    @Resource
    private UserInviteReceiveCouponService userInviteReceiveCouponService;
    @Resource
    private ConsumerFileService consumerFileService;
    @Resource
    private EventHandleService eventHandleService;
    @Resource
    private ConsumerRelateService consumerRelateService;
    @Resource
    private ConsumerPrivateService consumerPrivateService;

    private static int expireSeconds = 86400;

    /**
     * 查询用户上一次服务订单信息
     *
     * @param userId:
     * @return : java.lang.String
     * @author : gaozifeng
     * @date : 2019/7/16 10:25
     */
    public OrderCraftsmanResponseDTO lastService(Long userId) throws Throwable {
        if (null == userId) {
            throw new InputParamException(InputParamException.Type.NULL, "用户参数");
        }
        ConsumerTO consumerTO = getConsumerById(userId);
        ConsumerPrivateTO privateTO = consumerPrivateService.selectByPrimary(userId);
        OrderCraftsmanResponseDTO dto = new OrderCraftsmanResponseDTO()
                .setConsumerId(String.valueOf(userId)).setCraftsmanId("0").setOrderNo("").setShopId("0");
        if (null == privateTO) {
            dto = feignDomain.queryServices(String.valueOf(consumerTO.getId()));
        } else {
            if (null != privateTO.getPhone()) {
                List<ConsumerRelateTO> relateList = consumerRelateService
                        .selectConsumerRelateList(new ConsumerRelateQO().setPhone(privateTO.getPhone()));
                String ids = relateList.stream().map(a -> String.valueOf(a.getId())).collect(Collectors.joining(","));
                dto = feignDomain.queryServices(ids);
            }
        }
        return dto;
    }

    /**
     * 用户创建分享,返回id即为场景值
     *
     * @param shareTO:
     * @return : void
     * @author : gaozifeng
     * @date : 2019/7/10 17:26
     */
    @Transactional
    public Long createShare(ShareTO shareTO) throws Throwable {
        if (0L == shareTO.getConsumerId() || null == shareTO.getShareAim() || null == shareTO.getShareType() || null == shareTO.getShareFrom()) {
            throw new InputParamException(InputParamException.Type.EMPTY, "分享参数不能为");
        }
        ShareTO share = new ShareTO();
        share.setConsumerId(shareTO.getConsumerId()).setOrderNo(shareTO.getOrderNo())
                .setCraftsmanId(shareTO.getCraftsmanId()).setShopId(shareTO.getShopId())
                .setShareType(shareTO.getShareType()).setShareAim(shareTO.getShareAim())
                .setShareStatus(YesNoEnum.NO).setShareFrom(shareTO.getShareFrom())
                .setCreatedBy(shareTO.getConsumerId()).setIsDelete(YesNoEnum.NO);
        shareService.insert(share);
        return share.getId();
    }

    /**
     * 分享成功后的回调
     *
     * @param shareQO:
     * @return : void
     * @author : gaozifeng
     * @date : 2019/7/10 20:47
     */
    @Transactional
    public void shareRedirect(ShareQO shareQO) throws Throwable {
        if (null == shareQO || 0L == shareQO.getShareId() || 0L == shareQO.getConsumerId()) {
            log.info("分享修改参数不能为空");
            throw new InputParamException(InputParamException.Type.EMPTY, "分享不能为");
        }
        ShareTO shareTO = getShareById(shareQO.getShareId());

        shareService.update(shareTO.setShareStatus(YesNoEnum.YES).setUpdatedBy(shareQO.getConsumerId()));
    }

    /**
     * 获取临时二维码   失效重新生成二维码,并删除上一条
     *
     * @param :分享id
     * @return : java.lang.String
     * @author : gaozifeng
     * @date : 2019/7/10 19:57
     */
    @Transactional
    public String getTempQrCode(Long shareId,Long userId) throws Throwable {
        if (null == shareId || 0L == shareId) {
            throw new InputParamException(InputParamException.Type.EMPTY, "分享不能为");
        }
        //1、取已经生成的ticket
        ShareTO shareTO = getShareById(shareId);
        if (shareTO.getShareFrom() == ShareFromEnums.WX_MINA) {
            throw new DataException(DataException.Type.DEFAULT, "此分享不需要生成二维码链接");
        }
        List<WechatQrcodeTO> qrList = wechatQrcodeService.selectByQuery(new WechatQrcodeQO()
                .setSceneStr(ShareActEnums.CLAC.getDesc()).setSceneId(shareId).setReceiveId(userId).setIsDelete(YesNoEnum.NO));
        WechatQrcodeTO qrcodeTO;
        String ticket, qrUrl;
        Long sceneId;
        if (null == qrList || qrList.size() == 0) {
            sceneId = insertWechatQrCodeTable(shareId,userId);
            ticket = getTempQrCodeAndUpdateTableTicket(sceneId);
        } else {
            qrcodeTO = qrList.get(0);
            long createdTime = qrcodeTO.getCreatedTime().getTime();
            //剩余秒
            Long nowTime = System.currentTimeMillis();
            long lastTime = (nowTime - createdTime) / 1000;
            if (lastTime > 0 && expireSeconds - lastTime > 0) {
                //有效
                ticket = qrcodeTO.getTicket();
            } else {
                //失效  拉取新的ticket
                sceneId = insertWechatQrCodeTable(shareId,userId);
                ticket = getTempQrCodeAndUpdateTableTicket(sceneId);

                qrcodeTO.setIsDelete(YesNoEnum.YES);
                wechatQrcodeService.update(qrcodeTO);
            }
        }
        //请求URL 获取二维码;
        qrUrl = exChangeTempQrCode(ticket);
        return qrUrl;
    }

    /**
     * 领取记录
     *
     * @param scanDTO:
     * @return : void
     * @author : gaozifeng
     * @date : 2019/7/12 16:12
     */
    public void userInviteReceiveCouponService(ScanDTO scanDTO) throws Throwable {
        if (null == scanDTO.getSceneId() && null == scanDTO.getShareId()) {
            throw new InputParamException(InputParamException.Type.EMPTY, "领取参数不能为");
        }
        userInviteReceiveCouponService.receiveCoupon(scanDTO);
    }

    /**
     * 根据场景值获取用户头像
     *
     * @param shareId:
     * @return : java.lang.String
     * @author : gaozifeng
     * @date : 2019/7/12 16:13
     */
    public UserDTO getConsumerFileBySceneId(Long shareId) throws Throwable {
        ShareTO shareTO = getShareById(shareId);
        ConsumerTO consumerTO = consumerService.selectByPrimary(shareTO.getConsumerId());
        if (null == consumerTO) {
            throw new InputParamException(InputParamException.Type.EMPTY, "获取二维码信息参数不能为");
        }
        ConsumerFileQO fileQO = new ConsumerFileQO();
        fileQO.setConsumerId(consumerTO.getId());
        fileQO.setIsDelete(YesNoEnum.NO);
        List<ConsumerFileTO> fileTOList = consumerFileService.selectConsumerFileList(fileQO);
        UserDTO dto = new UserDTO();
        if (null == fileTOList || fileTOList.size() == 0) {
            log.info("根据场景值,用户没有头像[{}]",shareTO.getConsumerId());
            dto.setPath(ConsumerUtils.getDefaultConsumerPath());
        }else{
            ConsumerFileTO fileTO = fileTOList.get(0);
            if (null == fileTO.getPath()) {
                log.info("根据场景值,用户没有头像[{}]",shareTO.getConsumerId());
                dto.setPath(ConsumerUtils.getDefaultConsumerPath());
            } else {
                dto.setPath(fileTO.getPath());
            }
        }
        if (null == consumerTO.getName()) {
            log.info("根据场景值,用户没有名字[{}]",shareTO.getConsumerId());
            dto.setName(ConsumerUtils.getDefaultConsumerName());
        } else {
            dto.setName(Base64Utils.decoderParam(consumerTO.getName()));
        }
        dto.setId(consumerTO.getId());
        return dto;
    }

    /**
     * 获取当前二维码信息
     *
     * @param id:
     * @return : com.xingkeduo.pojo.table.WechatQrcodeTO
     * @author : gaozifeng
     * @date : 2019/7/11 17:54
     */
    public WechatQrcodeTO getWechatQrCodeInfoById(Long id) throws Throwable {
        if (null == id) {
            throw new InputParamException(InputParamException.Type.EMPTY, "获取二维码信息参数不能为");
        }
        WechatQrcodeTO wechatQrcodeTO = getWechatQrCodeById(id);
        return wechatQrcodeTO;
    }

    private ConsumerTO getConsumerById(Long userId) throws Throwable {
        ConsumerTO consumerTO = consumerService.selectByPrimary(userId);
        if (null == consumerTO) {
            throw new DataException(DataException.Type.NULL, "用户信息");
        }
        return consumerTO;
    }

    /**
     * ticket换取二维码
     *
     * @param ticket:
     * @return : java.lang.String
     * @author : gaozifeng
     * @date : 2019/7/10 21:43
     */
    private static String exChangeTempQrCode(String ticket) {
        String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s";
        String resultUrl = null;
        try {
            resultUrl = String.format(url,
                    URLEncoder.encode(ticket, StandardCharsets.UTF_8.name()));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            log.info("tikect换取二维码失败,msg[{}]", e.getMessage());
            throw new SystemException(SystemException.Type.DEFAULT, "二维码生成失败");
        }
        return resultUrl;
    }

    /**
     * 生成二维码表记录
     *
     * @param shareId:
     * @return : java.lang.Long
     * @author : gaozifeng
     * @date : 2019/7/12 10:11
     */
    private Long insertWechatQrCodeTable(Long shareId,Long userId) throws Throwable {
        WechatQrcodeTO wechatQrcodeTO = new WechatQrcodeTO();
        wechatQrcodeTO.setSceneStr(ShareActEnums.CLAC.getDesc())
                .setSceneId(shareId).setType(QrCodeExpireEnums.TEMP)
                .setCreatedTime(new Date()).setIsDelete(YesNoEnum.NO)
                .setStatus(QrCodeStatusEnums.EFFECTIVE).setReceiveId(userId)
                .setExpireSeconds(expireSeconds);
        wechatQrcodeService.insert(wechatQrcodeTO);
        long id = wechatQrcodeTO.getId();
        if (0L == id) {
            throw new SystemException(SystemException.Type.DEFAULT, "生成二维码记录出错");
        }
        return wechatQrcodeTO.getId();
    }

    /**
     * 获取二维码临时表 并修改ticket
     *
     * @param id:
     * @return : java.lang.String
     * @author : gaozifeng
     * @date : 2019/7/15 18:09
     */
    private String getTempQrCodeAndUpdateTableTicket(Long id) throws Throwable {
        QRCodeDTO qrCodeDTO = new QRCodeDTO(expireSeconds, id);

        String ticket = eventHandleService.eventHandle(SendingTypeEnum.QR_CODE, qrCodeDTO);

        WechatQrcodeTO wechatQrcodeTO = wechatQrcodeService.selectByPrimary(id);
        wechatQrcodeTO.setTicket(ticket);
        wechatQrcodeService.update(wechatQrcodeTO);
        return ticket;
    }


    /**
     * 根据二维码记录id 查询
     *
     * @param id:
     * @return : com.xingkeduo.pojo.table.WechatQrcodeTO
     * @author : gaozifeng
     * @date : 2019/7/12 10:11
     */
    private WechatQrcodeTO getWechatQrCodeById(Long id) throws Throwable {
        WechatQrcodeTO wechatQrcodeTO = wechatQrcodeService.selectByPrimary(id);
        if (null == wechatQrcodeTO) {
            throw new DataException(DataException.Type.NULL, "二维码记录");
        }
        return wechatQrcodeTO;
    }

    private ShareTO getShareById(Long shareId) throws Throwable {
        ShareTO shareTO = shareService.selectByPrimary(shareId);
        if (null == shareTO) {
            throw new DataException(DataException.Type.NULL, "分享记录");
        }
        return shareTO;
    }

}
